package org.devastra.arcinspect.core.data;

import java.util.ArrayList;
import java.util.List;

import org.devastra.arcinspect.core.data.cache.EntityInfoCache;

public abstract class AbstractEntityInfo implements EntityInfo, Comparable<EntityInfo> {

	private int id;
	private String name;
	private String qualName;
	private EntityType entityType; 
	private int parentId;
	private List<EntityInfo> refEntityInfoList;
	
	private static int entityCounter = 0;
	
	/**
	 * 
	 * @param _name
	 * @param _type
	 * @param _parentId
	 * /
	protected AbstractEntityInfo(String _name, EntityType _type, int _parentId) {
		//super();
		this.id = getNextId();
		this.name = _name;
		this.entityType = _type;
		this.qualName = EntityInfoCache.getEntityInfo(_parentId).getName()+"."+this.name;
		this.parentId = _parentId;
		this.refEntityInfoList = new ArrayList<EntityInfo>();
		
		EntityInfoCache.registerEntity(this);
	}
	*/
	
	/**
	 * To be used by package Entity
	 * @param _name
	 * @param parentId
	 * /
	protected AbstractEntityInfo(String _name, EntityType _type) {
		//super();
		this.id = getNextId();
		this.qualName = _name;
		this.entityType = _type;
		
		if(EntityType.PACKAGE == _type) {
			this.parentId = id;
			this.name = _name;
		} else {
			int lastDotPos = _name.lastIndexOf('.');
			if(lastDotPos == -1) {
				throw new RuntimeException("Need to pass fully qualified name to this constructor: "+_name+", entityYype: "+_type);
			}
			String pkgName = _name.substring(0, lastDotPos);
			//PackageInfo pkgInfo = PackageInfo.getPackage(pkgName);
			EntityInfo parentInfo = locateEntityInfo(pkgName);
			this.parentId = parentInfo.getId();
			this.name = _name.substring(lastDotPos+1);
		}
		
		EntityInfoCache.registerEntity(this);
	}
	*/
	
	protected AbstractEntityInfo(String _qualName, EntityType _type, boolean _shortName) {
		this.id = getNextId();
		this.refEntityInfoList = new ArrayList<EntityInfo>();
		updateData(_qualName, _type, _shortName);
		EntityInfoCache.registerEntity(this);
	}
	
	protected AbstractEntityInfo(EntityInfo _entity, EntityType _type, boolean _shortName) {
		this.id = _entity.getId();
		this.refEntityInfoList = new ArrayList<EntityInfo>();
		String qualName = _entity.getQualifiedName();
		
		updateData(qualName, _type, _shortName);
		/*
		int lastPos = qualName.lastIndexOf('.');
		String name = qualName.substring(lastPos+1);
		String parentName = qualName.substring(0, lastPos);
		EntityInfo parent = locateEntityInfo(parentName);
		
		this.entityType = _type;
		this.qualName = qualName;
		this.parentId = parent.getId();
		this.name = (_shortName)? name: qualName;
		*/
		
		EntityInfoCache.registerEntity(this);
	}
	
	/**
	 * Private helper method to update name, qualified name, parent id, etc.
	 * @param _qualName
	 * @param _type
	 * @param _shortName
	 */
	private void updateData(String _qualName, EntityType _type, boolean _shortName) {
		
		this.entityType = _type;
		this.qualName = _qualName;
		
		String name = null;
		//int parentId = -1;
		int lastPos = _qualName.lastIndexOf('.');
		
		if(lastPos == -1) {
			name = _qualName;
			this.parentId = -1;
		} else {
			name = _qualName.substring(lastPos+1);
			String parentName = _qualName.substring(0, lastPos);
			EntityInfo parent = locateEntityInfo(parentName);
			this.parentId = parent.getId();
		}
		
		this.name = (_shortName)? name: _qualName;
	}

	protected static int getNextId() {
		return ++entityCounter;
	}
	
	public int getParentId() {
		return parentId;
	}

	public void setParentId(int _parentId) {
		this.parentId = _parentId;
	}

	@Override
	public int getId() {
		return id;
	}
	
	@Override
	public String getName() {
		return name;
	}
	
	public void setName(String _name) {
		this.name = _name;
	}
	
	@Override
	public String getQualifiedName() {
		return qualName;
	}

	@Override
	public EntityInfo getParent() {
		return EntityInfoCache.getEntityInfo(parentId);
	}
	
	@Override
	public EntityType getType() {
		return entityType;
	}
	
	
	protected void setType(EntityType _type) {
		this.entityType = _type;
	}
	
	public void addReferencedEntityInfo(EntityInfo _pkgInfo) {
		refEntityInfoList.add(_pkgInfo);
	}
	
	public void addReferencedEntityInfo(List<PackageInfo> _pkgInfoList) {
		
		if(_pkgInfoList != null && _pkgInfoList.size() > 0) {
			refEntityInfoList.addAll(_pkgInfoList);
		}
	}
	
	@Override
	public List<EntityInfo> getReferencedEntityInfo() {
		return refEntityInfoList;
	}

	@Override
	public int compareTo(EntityInfo o) {
		return getId() - o.getId();
	}
	
	/**
	 * Helper method that finds existing EntityInfo object or create a new UnknownEntityInfo object
	 * 
	 * @param _name
	 * @return
	 */
	protected static synchronized EntityInfo locateEntityInfo(String _name) {
		EntityInfo info = EntityInfoCache.getEntityInfo(_name);
		if(info == null) {
			info = new UnknownEntityInfo(_name);
		}
		return info;
	}

}
